#include "cvector3d.h"

/**
 * CVector3D - constructor
 */
template <typename T>
CVector3D<T>::CVector3D() {
  this->init(this->VECTOR_SPACE_3D);
}
//---------------------------------------------------------------------------

/**
 * CVector3D - constructor, sets vector items
 * @param x
 * @param y
 * @param z
 */
template <typename T>
CVector3D<T>::CVector3D(T x, T y, T z) {
  this->init(this->VECTOR_SPACE_3D);
  setX(x);
  setY(y);
  setZ(z);
}
//---------------------------------------------------------------------------

/**
 * CVector3D - copy constructor
 * @param v
 */
template <typename T>
CVector3D<T>::CVector3D(const CVector3D<T> &v) {
  this->copyFrom(v);
}
//---------------------------------------------------------------------------

/**
 * CVector3D - copy constructor
 * @param v
 */
template <typename T>
CVector3D<T>::CVector3D(const CVectorBase<T> &v) {
 
  // If given vector does not have matching number of items, throw exception
  if (v.getSize() != this->VECTOR_SPACE_3D) {
    throw CInvalidSizeException(getClassName(), "CVector3D");
  }
  this->copyFrom(v);
}
//---------------------------------------------------------------------------

/**
 * ~CVector3D - destructor, free vector from memory
 */
template <typename T>
CVector3D<T>::~CVector3D() {
  this->free();
}
//---------------------------------------------------------------------------

/**
 * operator= - assign (copy) vector
 * @param v
 * @return this
 */
template <typename T>
CVector3D<T>& CVector3D<T>::operator = (const CVector3D<T> &v) {

  // Free memory, copy vector, return result
  this->free();
  this->copyFrom(v);
  return *this;
}
//---------------------------------------------------------------------------

/**
 * operator+ - sum of vectors
 * @param v
 * @return sum
 */
template <typename T>
CVector3D<T> CVector3D<T>::operator + (const CVector3D<T> &v) const {
  return CVector3D<T>(*this) += v;
}
//---------------------------------------------------------------------------

/**
 * operator- - difference of vectors
 * @param v
 * @return difference
 */
template <typename T>
CVector3D<T> CVector3D<T>::operator - (const CVector3D<T> &v) const {
  return CVector3D<T>(*this) -= v;
}
//---------------------------------------------------------------------------

/**
 * operator* - multiplies vector by number
 * @param num
 * @return multiplied vector
 */
template <typename T>
CVector3D<T> CVector3D<T>::operator * (T num) const {
  return CVector3D<T>(*this) *= num;
}
//---------------------------------------------------------------------------

/**
 * operator/ - divides vector by number
 * @param num
 * @return divided vector
 */
template <typename T>
CVector3D<T> CVector3D<T>::operator / (T num) const {
  return CVector3D<T>(*this) /= num;
}
//---------------------------------------------------------------------------

/**
 * getX - returns x axis position
 * @return x axis position
 */
template <typename T>
T CVector3D<T>::getX() const {
  return this->items[0];
}
//---------------------------------------------------------------------------

/**
 * getY - returns y axis position
 * @return y axis position
 */
template <typename T>
T CVector3D<T>::getY() const {
  return this->items[1];
}
//---------------------------------------------------------------------------

/**
 * getZ - returns z axis position
 * @return z axis position
 */
template <typename T>
T CVector3D<T>::getZ() const {
  return this->items[2];
}
//---------------------------------------------------------------------------

/**
 * setX - sets x axis position
 * @param x
 */
template <typename T>
void CVector3D<T>::setX(T x) {
  this->items[0] = x;
}
//---------------------------------------------------------------------------

/**
 * setY - sets y axis position
 * @param y
 */
template <typename T>
void CVector3D<T>::setY(T y) {
  this->items[1] = y;
}
//---------------------------------------------------------------------------

/**
 * setZ - sets z axis position
 * @param z
 */
template <typename T>
void CVector3D<T>::setZ(T z) {
  this->items[2] = z;
}
//---------------------------------------------------------------------------

/**
 * getSize - returns size (num of items) of vector
 * @return size of vector
 */
template <typename T>
TIndex CVector3D<T>::getSize() const {
  return this->VECTOR_SPACE_3D;
}
//---------------------------------------------------------------------------

/**
 * setSize - disables parent class method
 * @param size
 */
template <typename T>
void CVector3D<T>::setSize(TIndex size) {}
//---------------------------------------------------------------------------

/**
 * cross - cross product of two vectors
 * @param v1
 * @param v2
 * @return cross product
 */
template <typename T>
CVector3D<T> CVector3D<T>::cross(const CVector3D<T> &v1,
                                 const CVector3D<T> &v2) {
  return CVector3D<T>(v1.getY() * v2.getZ() - v1.getZ() * v2.getY(),
                      v1.getZ() * v2.getX() - v1.getX() * v2.getZ(),
                      v1.getX() * v2.getY() - v1.getY() * v2.getX());
}
//---------------------------------------------------------------------------

template class CVector3D<char>;
template class CVector3D<short>;
template class CVector3D<int>;
template class CVector3D<long>;
template class CVector3D<float>;
template class CVector3D<double>;
template class CVector3D<CBigInt>;
template class CVector3D<CFraction>;
